﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Text.RegularExpressions;

namespace Elentok.Common
{
  /// <summary>
  /// Fetches extended information about an assembly
  /// </summary>
  public class AssemblyExtendedInfo
  {
    /// <summary>
    /// Returns the value of the assembly's version (the "Version" property of the AssemblyName)
    /// </summary>
    public Version AssemblyVersion { get; private set; }
    /// <summary>
    /// Returns the value of the "FileVersion" attribute
    /// </summary>
    public string FileVersion { get; private set; }
    /// <summary>
    /// Returns the value of "InformationalVersion" attribute
    /// </summary>
    public string ProductVersion { get; private set; }
    /// <summary>
    /// Returns the value of the "Product" attribute
    /// </summary>
    public string Product { get; private set; }
    /// <summary>
    /// Returns the value of the "Title" attribute
    /// </summary>
    public string Title { get; private set; }
    /// <summary>
    /// Returns the value of the "Configuration" attribute
    /// </summary>
    public string Configuration { get; private set; }
    /// <summary>
    /// Returns true if this is a trunk version
    /// </summary>
    public bool IsTrunk { get; private set; }
    /// <summary>
    /// Returns the description of the assembly
    /// </summary>
    public string Description { get; private set; }
    /// <summary>
    /// Returns the copyrights of the assembly
    /// </summary>
    public string Copyrights { get; private set; }
    /// <summary>
    /// Returns the company of the assembly
    /// </summary>
    public string Company { get; private set; }

    private static T GetAttribute<T>(Assembly assembly) where T : Attribute
    {
      Type type = typeof(T);
      object[] attributes = assembly.GetCustomAttributes(type, false);
      if (attributes.Length == 1)
        return (T)attributes[0];

      return null;
      //if (attributes.Length == 0)
      //    throw new Exception("Assembly doesn't have " + type.Name);
      //else
      //    throw new Exception("Assembly has more than one " + type.Name);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TAttribute"></typeparam>
    /// <param name="assembly"></param>
    /// <param name="propertyName">The property of the attribute to return</param>
    /// <param name="defaultValue">The value to return if the attribute doesn't exist</param>
    /// <returns></returns>
    private static string GetAttributeValue<TAttribute>(Assembly assembly, string propertyName, string defaultValue)
      where TAttribute : Attribute
    {
      TAttribute attrib = GetAttribute<TAttribute>(assembly);
      if (attrib == null)
        return defaultValue;

      return (string)typeof(TAttribute).GetProperty(propertyName).GetGetMethod().Invoke(attrib, new object[] { });
    }

    private static string GetAttributeValue<TAttribute>(Assembly assembly, string propertyName)
      where TAttribute : Attribute
    {
      return GetAttributeValue<TAttribute>(assembly, propertyName, string.Empty);
    }
    
    /// <summary>
    /// Initializes an instance of the <see cref="AssemblyExtendedInfo"/> class
    /// </summary>
    /// <param name="assembly"></param>
    public AssemblyExtendedInfo(Assembly assembly)
    {
      AssemblyVersion = assembly.GetName().Version;
      Title = GetAttributeValue<AssemblyTitleAttribute>(assembly, "Title");
      Configuration = GetAttributeValue<AssemblyConfigurationAttribute>(assembly, "Configuration");
      Copyrights = GetAttributeValue<AssemblyCopyrightAttribute>(assembly, "Copyright");
      Description = GetAttributeValue<AssemblyDescriptionAttribute>(assembly, "Description");

      FileVersion = GetAttributeValue<AssemblyFileVersionAttribute>(assembly, "Version");
      Company = GetAttributeValue<AssemblyCompanyAttribute>(assembly, "Company");

      ProductVersion = GetAttributeValue<AssemblyInformationalVersionAttribute>(assembly, "InformationalVersion");
      Product = GetAttributeValue<AssemblyProductAttribute>(assembly, "Product");

      Regex regex = new Regex(
        "(^| )Trunk( |$)",
        RegexOptions.Compiled | RegexOptions.IgnoreCase);
      IsTrunk = regex.IsMatch(Configuration);
    }
  }
}
